iT邦幫忙

2023 iThome 鐵人賽

DAY 19
0
Software Development

LeetCode-30 Days of JavaScript系列 第 19

LeetCode JS30-Day19 | 2721. Execute Asynchronous Functions in Parallel 平行執行非同步函數

  • 分享至 

  • xImage
  •  

Day19 - 2721. Execute Asynchronous Functions in Parallel 平行執行非同步函數 Medium

Description❓

Given an array of asynchronous functions functions, return a new promise promise. Each function in the array accepts no arguments and returns a promise. All the promises should be executed in parallel.

promise resolves:

  • When all the promises returned from functions were resolved successfully in parallel. The resolved value of promise should be an array of all the resolved values of promises in the same order as they were in the functions. The promise should resolve when all the asynchronous functions in the array have completed execution in parallel.

promise rejects:

  • When any of the promises returned from functions were rejected. promise should also reject with the reason of the first rejection.

Please solve it without using the built-in Promise.all function.

給定一個異步函數functions陣列,傳回一個新的Promisepromise
數組中的每個函數不接受任何參數並傳回一個Promise。 所有Promise應該並行執行。

promise 解析:

  • 當從functions陣列返回的所有Promise都成功完成解析時。
  • promise 的解析值應該是一個包含所有 Promise 解析值的數組,其順序與它們在 functions 中的順序相同。
  • 當陣列中的所有異步函數都成功完成解析時,解析promise

promise 拒絕:

  • 當從函數返回的任何承諾被拒絕時。 Promise 也應該拒絕並給出第一次拒絕的原因。

請在不使用內建Promise.all函數的情況下解決該問題。

Points

Solution✍️

[ ▶️挑戰這一題 ][ 本日代碼 ]

  1. 給定一個異步函數“functions”數組,返回一個新的承諾“promise”。
    數組中的每個函數不接受任何參數並返回一個承諾。
  2. 當從“functions”返回的所有承諾都成功解決時。
    “promise”的解析值應該是“promise”的所有解析值的數組,其順序與“functions”中的順序相同。
var promiseAll = function(functions) {
  return new Promise((resolve, reject) => {
    const results = [];    //解析functions數組的邏輯
    for (let i = 0; i < functions.length; i++) {
      functions[i]()  
        //Promise resolve的情況 使用.then(result=>{...})處理promise執行結果
        .then(result => {  })
        //Promise reject的情況 使用.catch(error => { ... })處理promise錯誤信息
        .catch(error => {  });
    }
  });
};
  1. 解析functions陣列並將結果存入results陣列
    外部宣告變數resolvedCount來記錄目前results內已成功解析的 Promise 數量,
    當已成功解析的 Promise 數量與原function陣列元素數量相等,
    表示已全數解析完畢,使用 resolve() 返回結果。

  2. 當從“functions”返回的任何承諾被拒絕時。 “promise”也應該拒絕並給出第一次拒絕的理由。

  var promiseAll = function(functions) {
    return new Promise((resolve, reject) => {
      const results = [];
      let resolvedCount = 0;
  
      //解析functions數組的邏輯
      for (let i = 0; i < functions.length; i++) {
        functions[i]()
          .then(result => {
              results[i] = result;
              resolvedCount++;  
              if (resolvedCount === functions.length) { resolve(results);}
            })
          .catch(error => {
            console.log(`發生錯誤: ${error}`);
            reject(error);
          }); 
      }
    });
  };

補充

❓為什麼不直接用 (results.length === functions.length)判斷

因為.then 處理程序是非同步的,不會等待上個Promise是否已經解析成功。

//錯誤範例
var promiseAll = function(functions) {
  return new Promise((resolve, reject) => {
    const results = [];
    for (let i = 0; i < functions.length; i++) {
      functions[i]()
        .then(result => {
            results[i] = result;
            if (results.length === functions.length) { resolve(results);}
          })
        .catch(error => {reject(error);}); 
    }
  });
};

以下面Input為例

Input: functions = [
  () => new Promise(resolve => setTimeout(() => resolve(4), 50)), 
  () => new Promise(resolve => setTimeout(() => resolve(10), 150)), 
  () => new Promise(resolve => setTimeout(() => resolve(16), 100))
]

functions[1] 的解析時間比 functions[2] 長,當functions[2] 解析,並將結果存入 results[2]。
在 JavaScript 中,當你為數組的某個索引位置賦值時,
如果該索引超出了當前數組的長度,JavaScript 會自動擴展數組的長度以容納這個新元素。
這意味著數組的長度會根據最大的索引值來確定。

const ary = [];
ary[0] = 1;
ary[3] = 2;

在這個範例中,陣列的長度是 4,因為最大的索引是 3,所以長度是 3 + 1 = 4。

[1, undefined, undefined, 2]

所以functions[1]還沒解析完畢前,results陣列就會因為functions[2]解析完畢而擴展。

Testcase

let start = Date.now();
async function testcase(functions){
  let returnAry = await promiseAll(functions);
  let end = Date.now();
  let result ={
    "t":end-start,
    "resolved":returnAry,
  }
  console.log(result);
  console.log(`returnAry: [${returnAry}]`);
}
let functions1 = [
  () => new Promise(resolve => setTimeout(() => resolve(5), 200))
]
testcase(functions1);
//輸出
//{t: 210, resolved: Array(1)}
//returnAry: [5]
let functions2 = [
  () => new Promise(resolve => setTimeout(() => resolve(1), 200)), 
  () => new Promise((resolve, reject) => setTimeout(() => reject("Error"), 100))
]
testcase(functions2);
// 輸出
// 發生錯誤: Error
// Uncaught Error UnhandledPromiseRejection:...
let functions3 = [
  () => new Promise(resolve => setTimeout(() => resolve(4), 50)), 
  () => new Promise(resolve => setTimeout(() => resolve(10), 150)), 
  () => new Promise(resolve => setTimeout(() => resolve(16), 100))
]
testcase(functions3);
// 輸出
// {t: 161, resolved: Array(3)}
// returnAry: [4,10,16]

上一篇
LeetCode JS30-Day18 | 2627. Debounce函數防抖
下一篇
LeetCode JS30-Day20 | 2727. Is Object Empty 判斷物件是否為空
系列文
LeetCode-30 Days of JavaScript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言